Fantom-DE/Literale
Die folgenden Typen haben eine Syntax für Literale: * sys::Bool * sys::Int * sys::Float * sys::Decimal * sys::Str * sys::Duration * sys::Uri * sys::Type * sys::Slot * sys::Range * sys::List * sys::Map Die drei Typen Bool, Int und Float sind Werttypen. Diese Typen werden nicht unbedingt als Objektreferenzen übergeben, sondern stattdessen als Werte auf dem Aufrufstapel. Wenn Werttypen an oder von Referenztypen wie Obj der Num angepasst werden, generiert der Compiler automatisch Boxing- bzw. Unboxing-Operationen. Bool Von sys::Bool gibt es genau zwei Werte, die durch die Schlüsselwörter true und false repräsentiert werden. Als Wertypen habe Bool-Felder den Vorgabewert false anstelle von null. Der Vorgabewert von Bool? ist allerdings null. Int sys::Int dient dazu, vorzeichenbehaftete 64-Bit-Ganzzahlen zu repräsentieren. Fantom kennt keine ganzzahligen Typen mit geringerer Präzision. Außerdem verwendet Fantom Int auch dazu, einzelne Zeichen eines String als Unicode-Codepoint zu repräsentieren (was sich als praktisch erweist, da es tatsächlich mehr als 2^16 Unicode-Zeichen gibt). Int ist ein const-Typ, das heoßt, seine Instanzen sind immutabel. Int-Literale werden durch Ketten von Dezimalziffern ausgedrückt. Außerdem kann ein Int auch durch eine Hexadezimalzahl dargestellt werden, der 0x vorangestellt ist. Die Oktalnotation wird nicht unterstützt. Sie können an beliebiger Stelle innerhalb eines Int-Literals einen Unterstrich als Trennzeichen einfügen, um Ihren Code lesbarer zu gestalten. Fantom erlaubt auch Zeichenliterale im Stil von C, die einen Unicode-Codepoint als Int-Literal repräsentieren. Zeichenliterale sind in Hochkommas eingeschlossen und unterstützen die folgenden Escape-Sequenzen: \b \f \n \r \t \" \' \` \$ \\ \uXXXX Die letzte Escape-Sequenz \uXXXX bezeichnet einen Unicode-Codepoint in Form einer vierstelligen Hexadezimalzahl. Einige Beispiele für Int-Literale: 45 -89_039 0xcafebabe 0xCAFE_BABE '?' '\n' '\u03ab' '\u00F2' Als Wertyp hat ein Int-Feld den Vorgabewert 0 anstelle von null. Der Vorgabewert von Int? ist jedoch null. Float sys::Float dient dazu, 64-Bit-Fließkommazahlen zu repräsentieren. Für 32-Bit-Fließkommazahlen gibt es keinen Typ. Float ist const; das bedeutet, dass alle Instanzen immutabel sind. Float-Literale werden wie in C, Java usw. durch eine Kette von Dezimalziffen ausgedrückt, mit optionalem Punkt und Dezimalteil und optionalem Exponent. Ein f oder F als Suffix ist erforderlich, um Float-Zahlen von Dezimalzahlen unterscheiden zu können. Sie können den Unterstrich _ als Trennzeichen verwenden. Einige Beispiele für Float-Literale: 3.0f 3f 3.0F 123_456.0f 3e6f 0.2e+6f 1_2.3_7e-5_6f Als Wertyp hat ein Float-Feld den Vorgabewert 0.0f anstelle von null. Der Vorgabewert von Float? ist jedoch null. Decimal sys::Decimal dient dazu, immutable dezimale Fließkommazahlen zu repräsentieren, wobei die Präzision höher ist als die von Float. Dezimalzahlen eignen sich besonders für Finanzanwendungen, bei denen die Rundungsfehler von Float-Werten stören können. Sie werden in Java durch BigDecimal und in .NET durch System.Decimal implementiert. Decimal-Literale werden genau wie Float-Literale ausgedrückt, wobei jedoch das Suffix d bzw. D verwendet wird. Wenn ein Fließkomma-Literal mit Dezimalteil oder Exponent ohne Suffix dargestellt ist, wird es als Decimal verstanden. Einige Beispiele für Decimal-Literale: 4d 4.0 4.00 123_456d 3e6 0.2e+6D 1_2.3_7e-5_6 Hinweis: Dezimalzahlen verhalten sich auf den Plattformen Java und .NET nicht genau gleich. In Java wird der Typ BigDecimal verwendet, dessen Größe nicht beschränkt ist. In .NET wird dagegen System.Decimal verwende, das 28 signifikante Ziffern hat und den Bereich von 1E-28 bis 7.9E+28 umfasst. Außerdem gibt es einen Unterschied bezüglich der Gleichheit zwischen beiden Plattformen: 3.00 3.0 => false bei Java 3.00 3.0 => true bei .NET 3.00 <=> 3.0 => null auf beiden Plattformen Java behandelt nachfolgende Nullen als signifikant bezüglich der Gleichheit; in .NET sind sie dagegen insignifikant. Bei der Methode Obj.compare sind die Ergebnisse auf beiden Plattformen dagegen konsistent. Str sys::Str dient dazu, eine Folge von Unicode-Zeichen zu repräsentieren. Str ist const, das heißt, dass ale Instanzen von Str immutabel sind. Wenn Sie eine mutable Zeichenfolge benötigen, verwenden Sie stattdessen sys::StrBuf. Str-Literale werden durch doppelte Anführungszeichen (" ") eingeschlossen. Sonderzeichen können durch dieselben Escape-Sequenzen ausgedrückt werden, die oben für Int-Zeichenliterale angegeben sind. Ein paar Beispiele für Str-Literale: "Hallo" "Zeile 1\nZeile2" "Draußen sind 33\u00B0 Grad Celsius!" Mehzeilige Zeichenketten Str-Literale können über mehrere Zeilen reichen. Dabei werden die Zeilenumbrüche immer durch \n-Zeichen normalisiert, egal wie sie im Text des Quellprogramms kodiert sind. Das erste nicht-leere Zeichen in jeder Zeile muss rechts von dem öffnenden Anführungszeichen angeordnet sein; andernfalls gibt es einen Compiler-Fehler: x := "Zeile 1 Zeile 2 Zeile 3" Das obige Beispiel wird zu "Zeile 1\n Zeile2\nZeile 3" kompiliert. Beachten Sie, dass Leerzeichen rechts vom Anführungszeichen erhalten bleiben, während alle Zeichen links davon abgeschnitten werden. Wenn Sie Tab-Zeichen verwenden, müssen Sie die passende Anzahl von Tabs gefolgt von Leerzeichen einfügen: \t\tx := "line 1 \t\t line 2" Interpolation Str literals support string interpolation which allow arbitrary Fantom expressions to be embedded inside the string literals. Embedded expressions are prefixed using the $ dollar sign and surrounded with { and } braces. If the expression is a simple identifier or sequence of dotted identifiers then the braces may be omitted. Use the \$ escape sequence if you wish to express the dollar sign itself. Eine interpolierte Zeichenkette ist ein Ausdruck, der zur Laufzeit einen neuen Str erzeugt. Eigentlich handelt es sich um Syntax-Zucker für die Stringverkettung. Zum Beispiel ist: "x is $x, in hex $x.toHex, and x+8 is ${x+8}" gleichbedeutend wie: "x is " + x + ", in hex " + x.toHex + ", and x+8 is " + (x+8) Durch String-Interpolation ist die Formatierung von Zeichenketten leichter zu lesen und zu schreiben. Den Programmierkonventionen von Fantom zufolge sollte String-Interpolation immer anstellen von String-Verkettung benutzt werden. Dreifache Anführungszeichen Fantom kennt auch String-Literale mit dreifachen doppelten Anführungszeichen ("""). Diese funktionieren genau so wie normale String-Literale; der einzige Unterschied besteht darin, dass das doppelte Anführungszeichen (") darin nicht mit einer Escape-Sequenz dargestellt werden muss: echo("""Do you know "What lies beneath the shadow of the statue"?""") Str-DSL Sie können ein Str-Literal auch mit Hilfe der DSL-Syntax schreiben. Eine Str-DSL kann jeden beliebigen Buchstaben außer der Zeichenfolge |> enthalten. Auch die beiden Zeichen \ und $ haben keine besondere Bedeutung: echo(Str <|kein \ oder $ braucht eine Escape-Sequenz und auch mehrzeilig ist möglich|>) Str-DSL-Literale können sich über mehrere Zeilen erstrecken, wobei die Regeln für Leerzeichen wie bei normalen Strings anzuwenden sind. Duration (Zeitdauer) In Java verwenden APIs, die ein Maß für die Zeit benötigen, typischerweise ein long mit der Anzahl der Millisekunden. Dies führt zu einer gewissen uneindeutigkeit und wird problematisch, wenn man eine größere Genauigkeit benötigt. Fantom-APIs verwenden für die Zeit immer einen typisierten Wert. Absolute Zeitmaße werden durch sys::DateTime und relative Zeitmaße werden durch sys::Duration repräsentiert - beide normalisiert mit Nanosekunden-Genauigkeit. Beispielsweise können Sie für einen Wert von 5 Sekunden mit Hilfe des Konstruktors Duration.make folgendermaßen ausdrücken: Duration.make(5_000_000_000) // Langform Duration(5_000_000_000) // Kurzform Die vielen Nullen machen den Ausdruck aber unhandlich. Außerdem ist dies etwas ineffizient, denn jedes Mal, wenn dieser Ausdruck ausgeführt wird, muss ein Duration-Instanz erzeugt werden. In Fantom kann man die Zeitdauer auch mit Hilfe einer Literalsyntax ausdrücken, die aus einer Dezimalzahl mit optionalem, durch Punkt getrennten Dezimalteil und einem der Folgenden Suffixe besteht: Hier sind einige Beispiele für Duration-Literale: 4ns 100ms -0.5hr Uri Die Klasse sys::Uri repräsentiert einen _Uniform Resource Identifier_ (URI) und bildet die Grundlage für das Naming-Subsystem von Fantom. Uri hat eine eigen Literal-Syntax mit rückwärts geneigten Hochkommas (Backticks): `index.html` `/some/path/file.txt` `http://fantom.org/` `TPS Report.doc` Wenn Wir in Fantom mit URIs arbeiten und sie als Literale repräsentieren, verwenden wir immer die Standardform. Beispielsweise wird ein Leerzeichen durch ein Leerzeichen repräsentiert und nicht als %20 kodiert: `TPS Report.doc`.toStr // ergibt "TPS Report.doc" `TPS Report.doc`.encode // ergibt "TPS%20Report.doc" `TPS%20Report.doc`.toStr // ergibt "TPS%20Report.doc" `TPS%20Report.doc`.encode // ergibt "TPS%2520Report.doc" Genau wie Strings können auch Uri-Literale die standardmäßigen Escape-Sequenzen einschließlich Unicode-Codepoints enthalten. Unicode-Zeichen werden in UTF-8-Oktette kodiert, bevor der URI gemäß RFC 3986 Prozent-kodiert wird (siehe **sys::Uri.encode**). URIs können nach denselben Regeln wie String interpoliert werden: file := "file.txt" `/dir/$file` => ("/dir/" + file).toUri Type Die Klasse sys::Type bildet die Grundlage der Reflection-API von Fantom. Typischerweise untersucht man Typ-Instanzen mit Hilfe der Methode sys::Type.of. Man kann aber eine Typ-Instanz auch durch eine Literalsyntax repräsentieren, die einfach aus dem Typnamen und dem Zeichen # besteht. Str# acme::SomeType# Wenn kein voll qualifizierter Typname angegeben ist, dann wird der Typname entsprechend der Quelldatei aufgelöst, in der sich die Anweisungen befinden. Slot Ein Slot-Literal kann man mit der folgenden Syntax erzeugen: Int#plus #echo Wenn der Typname nicht angegeben ist, dann wird das Slot-Literal gegen die umschließende Klasse aufgelöst. Ein Slot-Literal wird entwender zu einer sys::Field- oder einer sys::Method-Instanz aufgelöst. Slot-Literale haben dieselbe Semantik wie Reflection über Type.slot, können allerdings vom Compiler statisch geprüft werden. Range (Wertebereich) Ein sys::Range repräsentiert einen zusammenhängenden Bereich von Ganzzahlen vom Anfang bis zum Ende. Ein Range kann im Fantom-Quellcode durch ein Literal in der Form anfang..ende für einen inklusiven oder anfang.. für einen exklusiven Wertebereich dargestellt werden (wobei der Anfang immer inklusiv ist). Einige Beispiele für Range-Literale: 0..5 // 0 bis 5 (Ende inklusiv) 0..<5 // 0 bis 4 (Ende exklusiv) x.... und ..< entsprechend der Operator-Präzedenz mit beliebigen Ausdrücken verwendet werden können. Sie sind nichts weiter als Syntaxzucker für die Erzeugung eines Range mit sys::Range.make. List Die Klasse sys::List speichert eine geordnete Liste mit Objekten. Listen können mit Hilfe der folgenden Literalsyntax instantiiert werden: // Syntax-Format wenn V der Optionale Elementtyp // und die Elemente beliebige Ausdrücke sind: Vitem1, ... itemN // Beispiele Int20, 30 // Liste der drei Int-Werte 10, 20 und 30 20, 30 // Dasselbe mit Typinferenz Int, // Leere Int-Liste , // Leere Obj?-Liste In den einfachsten Fällen ist ein List-Literal einfach eine Liste Komma-separierter Ausdrücke in eckigen Klammern. Wenn der Typpräfix fehlt, wird der Typ der Elemente durch Inferenz ermittelt. Undzwar wird der Typ der Elemente bestimmt, indem die spezifischste Klasse ermittelt wird, die allen Elementen gemeinsam ist (wobei Mixin-Typen nicht berücksichtigt werden). Ein Beispiel: 2, 3 // ergibt Int[] null, 3 // ergibt Int?[] 2f, 3f // ergibt Float[] 2f, 3 // ergibt Num[] "2", 3 // ergibt Obj[] Num2, 3 // ergibt Num[] [10,20, 30] // ergibt Int[][] Im Falle von 1,2f,3 enthält die Liste sowohl Int- also auch Float-Werte, deren spezifischste gemeinsame Basisklasse Num ist. Dagegen enthält die Liste 1,"2",3 Int- und Str-Werte, die keine gemeinsame Basisklasse außer Obj haben. Die Liste Num1,2,3 würde Int[] ergeben, wenn Typinferenz angewendet werden würde, aber wenn wir möglicherweise später Float-Zahlen in die Liste packen wollen, müssen wir die Typ explizit angeben. Häufig ermittelt der Compiler einen nicht-nullbaren Listentyp. Wenn in der Liste auch Nullwerte gespeichert werden sollen, muss sie ausdrücklich typisiert werden: 1,2,3 // kann keine null aufnehmen Int?1,2,3 // kann auch null aufnehmen Die leere Liste wird durch die spezielle Syntax , bezeichnet. In der Regel wird man einen Typ angeben, z.B. ist Str, eine leere Liste von Strings. Wenn kein Typ angegeben ist, dann ergibt die leere Liste ein Obj?,. Wenn ein Listenliteral ohne explizte Typangabe als Feld-Initialisierer verwendet wird, dann wird ihr Typ aus dem deklarierten Typ des Feldes ermittelt: Str[] names := , // Angangswert als Str, ermittelt Num[] nums := Int, // Anfangswert ist Int, Siehe Appendix bezüglich der formalen Regeln, die für die Typinferenz bei Listen angewendet werden. Map Die Klasse sys::Map speichert eine Menge von Schlüssel-Wert-Paaren unter Verwendung einer Hashtable. Maps können mit Hilfe der folgenden Syntax initialisiert werden: // Syntaxformat mit K:V als optionalem Map-Typ // und die Schlüssel und Werte als beliebige Ausdrücke: V:Kschlüssel1:wert1, ... schlüsselN:wertN // Beispiele Int:Str2:"zwei" // Map aus String mit Int als Schlüssel Int:Str2:"zwei" // wie oben in Kurzform 2:"zwei" // Wie oben mit Typinferenz Int:Str: // Leere Map des Typs Int:Str : // Leere Map des Typs Obj:Obj? Die Literalsyntax für Maps ist genau so wie die für Listen, nur dass wir die Schlüssel-Wert-Paare mit einem Doppelpunkt angeben. Der Typpräfix eines Map-Literals kann eine beliebige gültige Map-Signatur sein. Wenn der Typpräfix weggelassen ist, dann werden die Typen der Schlüssel und Werte nach den selben Regeln durch Inferenz ermittelt wie bei den List-Literalen. Zum Beispiel: 2:"zwei" // ergibt Int:Str 2:null // ergibt Int:Str? 2f:"zwei" // ergibt Num:Str 2f:null // ergibt Num:Str? 2f:0xabcd // ergibt Num:Obj [0:"eins"] // ergibt Int:Str[] Die leere Map wird durch die spezielle Syntax : mit oder ohne Typpräfix bezeichnet. Beachten Sie, dass der Schlüsseltyp einer Map nicht nullbar sein darf. Wenn Sie Typinferenz nutzen, müssen Sie eine Map, die Null-Werte speichern soll, explizit typisieren: 2:"two" // kann keine Nullwerte aufnehmen Int:Str?2:"two" // kann auch Nullwerte aufnehmen Der Typ Int:Str? ist eine Map mit Int-Schlüsseln und Str?-Werten. Dagegen ist der Typ Int:Str? eine des Typs Int:Str, wobei die Map-Variable selbst null sein kann. Wenn ein Map-Literal ohne explizitem Typ als Feldinitialisierer verwendet wird, dass wird ihre Typ anhand des deklarierten Feldtyps bestimmt: Str:File[] files := : // Initialwert ist Str:File: Kategorie: